/* Copyright 2017 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package credentials loads certificates and validates user credentials.
package gnmi

import (
	"encoding/base64"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/metadata"
)

var (
	usernameKey = "username"
	passwordKey = "password"
)

type basicAuth struct {
	username string
	password string
}

// GetRequestMetadata 定义授权信息的具体存放形式，最终会按这个格式存放到 metadata map 中。
func (a *basicAuth) GetRequestMetadata(context.Context, ...string) (map[string]string, error) {
	auth := a.username + ":" + a.password
	enc := base64.StdEncoding.EncodeToString([]byte(auth))
	return map[string]string{"authorization": "Basic " + enc}, nil
}

// RequireTransportSecurity 是否需要基于 TLS 加密连接进行安全传输
func (a *basicAuth) RequireTransportSecurity() bool {
	return false
}

// ClientCredentials generates gRPC DialOptions for existing credentials.
func ClientCredentials(user string, pwd string) []grpc.DialOption {

	basicAuth := &basicAuth{username: user, password: pwd}
	return []grpc.DialOption{
		// 不启用 tls
		grpc.WithTransportCredentials(insecure.NewCredentials()),
		// basic auth认证
		grpc.WithPerRPCCredentials(basicAuth),
	}

}

// AttachToContext attaches credentials to a context.
// If there are existing credentials, it overrides their values.
func AttachToContext(ctx context.Context, user string, pwd string) context.Context {

	md, ok := metadata.FromOutgoingContext(ctx)
	if !ok {
		md = metadata.MD{}
	}
	md.Set(usernameKey, user)
	md.Set(passwordKey, pwd)

	return metadata.NewOutgoingContext(ctx, md)
}
